/**
 * 2024/01/01 - 2024/12/31
 **/
package com.snail.camunda.engin.identity.holder;

import com.snail.camunda.engin.errorcode.CamundaErrorCode;
import com.snail.camunda.engin.identity.dto.UserInsertDTO;
import com.snail.camunda.engin.identity.dto.UserModifyDTO;
import com.snail.camunda.engin.identity.dto.UserQueryDTO;
import com.snail.start.utils.id.ObjectId;
import com.snail.starter.commons.exception.BizException;
import com.snail.starter.commons.page.PageQO;
import com.snail.starter.commons.page.PageVO;
import org.camunda.bpm.engine.IdentityService;
import org.camunda.bpm.engine.identity.Group;
import org.camunda.bpm.engine.identity.Tenant;
import org.camunda.bpm.engine.identity.User;
import org.camunda.bpm.engine.identity.UserQuery;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @author: (zg)
 * @Date: 2024/12/16 13:13
 * @Version: 1.0.0
 */
@Component
public class UserHolder {

    @Resource
    IdentityService identityService;

    public String add(Tenant tenant, Group group, UserInsertDTO dto) {
        User user = identityService.newUser(String.valueOf(ObjectId.nextLongId()));
        user.setFirstName(dto.getFirstName());
        user.setLastName(dto.getLastName());
        user.setEmail(dto.getEmail());
        user.setPassword(dto.getPassword());
        identityService.saveUser(user);
        if (null != tenant) {
            identityService.createTenantUserMembership(tenant.getId(), user.getId());
        }
        if (null != group) {
            identityService.createMembership(group.getId(), user.getId());
        }
        return user.getId();
    }

    public boolean modify(String id, UserModifyDTO dto) {
        User user = queryById(id);
        if (null == user) {
            throw BizException.of(CamundaErrorCode.USER_NOT_EXISTS);
        }
        if (null == dto) {
            return true;
        }
        if (null != dto.getEmail()) {
            user.setEmail(dto.getEmail());
        }
        if (null != dto.getFirstName()) {
            user.setFirstName(dto.getFirstName());
        }
        if (null != dto.getLastName()) {
            user.setLastName(dto.getLastName());
        }
        if (null != dto.getPassword()) {
            user.setPassword(dto.getPassword());
        }
        return true;
    }

    public User queryById(String id) {
        UserQuery userQuery = identityService.createUserQuery();
        return userQuery.userId(id).singleResult();
    }

    public boolean deleteById(String id) {
        identityService.deleteUser(id);
        return true;
    }

    public List<User> list(UserQueryDTO dto) {
        return createUserQuery(dto).list();
    }

    public UserQuery createUserQuery(UserQueryDTO dto) {
        UserQuery userQuery = identityService.createUserQuery();
        if (null != dto.getTenantId()) {
            userQuery.memberOfTenant(dto.getTenantId());
        }
        if (null != dto.getGroupId()) {
            userQuery.memberOfGroup(dto.getGroupId());
        }
        if (null != dto.getName()) {
            userQuery.userLastNameLike("%" + dto.getName() + "%").userFirstNameLike("%" + dto.getName() + "%");
        }
        if (null != dto.getEmail()) {
            userQuery.userEmailLike("%" + dto.getEmail() + "%");
        }
        return userQuery;
    }

    public PageVO<User> page(PageQO<UserQueryDTO> page) {
        return page(page, user -> user);
    }

    public <T> PageVO<T> page(PageQO<UserQueryDTO> page, Function<User, T> function) {
        UserQuery userQuery = createUserQuery(page.getQuery());
        long count = userQuery.count();
        if (0L == count) {
            return PageVO.of(page.getPageNum() - 1, page.getPageSize(), 0L, new ArrayList<>());
        }
        List<User> users = userQuery.listPage(page.getPageNum(), page.getPageSize());
        if (null == users || users.isEmpty()) {
            return PageVO.of(page.getPageNum(), page.getPageSize(), count, new ArrayList<>());
        }
        return PageVO.of(page.getPageNum(), page.getPageSize(), count, users.stream().map(function).collect(Collectors.toList()));
    }

}